import esbuild from "esbuild";
import { spawn } from "child_process";
import electron from "electron";

export const devPlugin = () => {
  return {
    name: "dev-plugin", // 插件的名称
    // 一个异步方法，用于配制服务器
    // 接受一个参数，该参数是vite开发服务器的实例
    async configureServer(service) {
      // 第一步：需要使用esbuild 同步构建项目
      esbuild.buildSync({
        entryPoints: ["./src/main/mainEntry.js"], // 对象项目的入口文件路径
        bundle: true, // 启用打包，将依赖一起打包成一额文件
        platform: "node", // 指定平台为node，主要是为了Electron 主进程服务
        format: "esm", // 模块的格式
        outfile: "./dist/mainEntry.js", // 出口文件路径
        external: ["electron"], // 外部依赖，避免被打包进去
      });
      // 接下来，需要监听服务器的listen事件，当监听到服务器启动时，执行构建
      service.httpServer.once("listening", () => {
        // 监听后启动electeon

        // 获取服务器的地址信息，包括IP、端口
        const addressInfo = service.httpServer.address();
        // 构造服务器的http地址字符串
        const httpAddress = `http://${addressInfo.address}:${addressInfo.port}`;
        // 开启子进程，启动electron
        const electronProcess = spawn(
          electron,
          ["./dist/mainEntry.js", httpAddress],
          {
            cwd: process.cwd(), // 子进程electron的当前工作目录
            stdio: "inherit", // 继承父进程的标准输入输出
          }
        );
        // 监听进程关闭事件， 关闭服务
        electronProcess.on(" close", () => {
          service.close(); // 关闭vite开发服务器
          process.exit(); // 退出当前进程
        });
      });
    },
  };
};

/**
 * 在这个插件中，主要事情就是替换工作， 包括
 * 1. Node.js 常见的模块，比如：path、fs、os等等
 * 2. Electron 的模块，比如：ipcRenderer、remote等等
 */
export const getReplacer = () => {
  // 该数组存放了一些 Node.js 下常用模块
  let externalModels = [
    "os",
    "fs",
    "path",
    "events",
    "child_process",
    "crypto",
    "http",
    "buffer",
    "url",
    "better-sqlite3",
    "knex",
  ];
  // 该对象用于存储最终的替换结果
  let result = {};
  for (let item of externalModels) {
    result[item] = () => ({
      find: new RegExp(`^${item}$`),
      code: `const ${item} = require('${item}'); export { ${item} as default }`,
    });
  }

  // 处理 electron 对应的模块，处理的思路和上面的 node.js 的处理思路是一样。
  result["electron"] = () => {
    let electronModules = [
      "clipboard",
      "ipcRenderer",
      "nativeImage",
      "shell",
      "webFrame",
    ].join(",");
    return {
      find: new RegExp(`^electron$`), // 使用该正则去匹配 electron 模块
      code: `const { ${electronModules} } = require('electron'); export { ${electronModules} }`, // 要生成的代码片段
    };
  };
  return result;
};
